#include "VAGDI.h"
#include "VFunctions.h"
#include <QDebug>
#include <windows.h>
#include <QRegularExpression>
#include <QRegularExpressionMatch>

VAGDI::VAGDI(QObject *parent):QObject(parent)
{
//    hMod = LoadLibrary(TEXT("VDM51.dll"));//dll路径
//    AG_AllReg_hook = (AG_AllReg_typedef)GetProcAddress(hMod, "DllUv3Cap");
//    AG_BpInfo_hook = (AG_BpInfo_typedef)GetProcAddress(hMod, "AG_BpInfo");
//    AG_BreakFunc_hook = (AG_BreakFunc_typedef)GetProcAddress(hMod, "AG_BreakFunc");
//    AG_GoStep_hook = (AG_GoStep_typedef)GetProcAddress(hMod, "AG_GoStep");
//    AG_HistFunc_hook = (AG_HistFunc_typedef)GetProcAddress(hMod, "AG_HistFunc");
//    AG_Init_hook = (AG_Init_typedef)GetProcAddress(hMod, "AG_Init");
//    AG_MemAcc_hook = (AG_MemAcc_typedef)GetProcAddress(hMod, "AG_MemAcc");
//    AG_MemAtt_hook = (AG_MemAtt_typedef)GetProcAddress(hMod, "AG_MemAtt");
//    AG_RegAcc_hook = (AG_RegAcc_typedef)GetProcAddress(hMod, "AG_RegAcc");
//    AG_Serial_hook = (AG_Serial_typedef)GetProcAddress(hMod, "AG_Serial");
//    DllUv3Cap_hook = (DllUv3Cap_typedef)GetProcAddress(hMod, "DllUv3Cap");
//    EnumUv351_hook = (EnumUv351_typedef)GetProcAddress(hMod, "EnumUv351");
}

// callback
U32 callback_func (U32 nCode, void *vp)
{
    qDebug() << "nCode" << nCode;
    return 0;
}

VAGDI::~VAGDI()
{
}

void VAGDI::load_library()
{
    hMod = LoadLibrary(TEXT("VDM51.dll"));//dll路径
    AG_AllReg_hook = (AG_AllReg_typedef)GetProcAddress(hMod, "DllUv3Cap");
    AG_BpInfo_hook = (AG_BpInfo_typedef)GetProcAddress(hMod, "AG_BpInfo");
    AG_BreakFunc_hook = (AG_BreakFunc_typedef)GetProcAddress(hMod, "AG_BreakFunc");
    AG_GoStep_hook = (AG_GoStep_typedef)GetProcAddress(hMod, "AG_GoStep");
    AG_HistFunc_hook = (AG_HistFunc_typedef)GetProcAddress(hMod, "AG_HistFunc");
    AG_Init_hook = (AG_Init_typedef)GetProcAddress(hMod, "AG_Init");
    AG_MemAcc_hook = (AG_MemAcc_typedef)GetProcAddress(hMod, "AG_MemAcc");
    AG_MemAtt_hook = (AG_MemAtt_typedef)GetProcAddress(hMod, "AG_MemAtt");
    AG_RegAcc_hook = (AG_RegAcc_typedef)GetProcAddress(hMod, "AG_RegAcc");
    AG_Serial_hook = (AG_Serial_typedef)GetProcAddress(hMod, "AG_Serial");
    DllUv3Cap_hook = (DllUv3Cap_typedef)GetProcAddress(hMod, "DllUv3Cap");
    EnumUv351_hook = (EnumUv351_typedef)GetProcAddress(hMod, "EnumUv351");
    callback = callback_func;
    _is_debug = true;
}

void VAGDI::release_library()
{
    FreeLibrary(hMod);
}

int VAGDI::AG_GoStep()
{
	
    AG_GoStep_hook(AG_NSTEP, 1, nullptr);
    return 0;
}

int VAGDI::ag_go_breakpoint()
{
    AG_GoStep_hook(AG_GOFORBRK, 0, nullptr);
    return 0;
}

int VAGDI::EnumUv351()
{
    typedef int(*EnumUv351_typedef)(void *p, DWORD nCode);
    EnumUv351_typedef EnumUv351_hook;



    struct dbgblk pdbg;
    strcpy(pdbg.MainDll, "C:\Keil_v5\C51\BIN\S8051.DLL");
    strcpy(pdbg.PeriDll, "C:\Keil_v5\C51\BIN\TP51.DLL");
    strcpy(pdbg.PeriArgs, "-p51");

    strcpy(pdbg.TargDll, "C:\\Users\\hong\\Documents\\untitled20\\build-untitled20-Desktop_Qt_5_6_2_MinGW_32bit-Debug\\debug\\hook.dll");
    strcpy(pdbg.TargArgs, "-A127.0.0.1 -P8000 -O2");

    pdbg.Clock = 12000000;

    pdbg.RomSz = 0;
    pdbg.uocArit = 0;
    pdbg.uocMdpt = 0;
    pdbg.uocXRAM = 0;
    pdbg.hadIRAM = 1;
    pdbg.hadXRAM = 0;
    pdbg.hadIROM = 1;
    pdbg.Moda2 = 0;
    pdbg.Moddp2 = 0;
    pdbg.Modp2 = 0;
    pdbg.Mod517dp = 0;
    pdbg.Mod517au = 0;
    pdbg.Mode2 = 0;
    pdbg.ModAB2 = 0;
    pdbg.useCB = 0;
    pdbg.useXB = 0;
    pdbg.Moddp2x = 0;
    pdbg.Mod390 = 0;
    pdbg.ModC812 = 0;
//    pdbg.Device = 0;
    pdbg.cBanks = 0;
    pdbg.xBanks = 0;

    pdbg.rCB.mTyp = 0;
    pdbg.rCB.nStart = 0;
    pdbg.rCB.nSize = 65535;

    pdbg.rXB.mTyp = 0;
    pdbg.rXB.nStart = 0;
    pdbg.rXB.nSize = 0;

    pdbg.irom.mTyp = 1;
    pdbg.irom.nStart = 0;
    pdbg.irom.nSize = 4096;

    pdbg.iram.mTyp = 0;
    pdbg.iram.nStart = 0;
    pdbg.iram.nSize = 128;


    EnumUv351_hook = (EnumUv351_typedef)GetProcAddress(hMod, "EnumUv351");
    int result = EnumUv351_hook((void*)&pdbg, 2);

    qDebug() << result;
    return 0;
}

int VAGDI::DllUv3Cap()
{
    QDLL pQ;

    pQ.parent = (HWND)_main_handle;
    pQ.pathUv3 = new_string("C:/Users/hong/Documents/untitled20/build-untitled20-Desktop_Qt_5_6_2_MinGW_32bit-Debug/debug/hook.dll", 200);
    pQ.Linst = hMod;
    pQ.ValSize = 65024;
    pQ.key = new_string("hook", 5);
    //QString("-A127.0.0.1 -P8000 -O0").toStdString().data()
    pQ.value = new_string("-A127.0.0.1 -P8000 -O0", 600);
    // pQ.prjname = QString("C:/Users/hong/a_Target 1.cfg").toStdString().data();

    int result = DllUv3Cap_hook(1, &pQ);
    qDebug() << pQ.value;

    qDebug() << result;
    return 0;
}

void VAGDI::ag_step_out()
{
    // (U16 nCode, UC8 *pB, GADR *pA, UL32 nMany);
    // 读取sp
    unsigned char buf[2] = {};
    GADR pA;
    pA.Adr = 0xF0000081;
    AG_MemAcc_hook(AG_READ, buf, &pA, 1);
    qDebug() << "sp:" << buf[0];

	pA.Adr = 0xF3000000 | (buf[0]-1);
	AG_MemAcc_hook(AG_READ, buf, &pA, 2);
	qDebug() << "sp data:" << buf[1]*256 + buf[0];

    unsigned int addr = buf[1]*256 + buf[0];
    if(addr != 0){
        pA.Adr = 0xFF000000 | addr;
        AG_GoStep_hook(AG_GOTILADR, 0, &pA);
    }


//    int i=0;
//    while(_ret_symbol[0x00FFFFFF&_pc] == 0){
//        AG_GoStep();
//        i ++;
//    }

}

void VAGDI::ag_step_over()
{
    int len = _call_symbol[0x00FFFFFF&_pc];
    if(len != 0){
        GADR pA;
        pA.Adr = _pc + len;
        AG_GoStep_hook(AG_GOTILADR, 0, &pA);
    }else{
        ag_step_into();
    }
}

void VAGDI::ag_step_into()
{
    AG_GoStep_hook(AG_NSTEP, 1, nullptr);
}

void VAGDI::ag_stop()
{
	//FreeLibrary(hMod);
    try {
        AG_Init_hook(0x40c, 0);
    }
    catch(...) {
        qDebug() << "error";
    }
    FreeLibrary(hMod);
    _is_debug = false;
    
}











void VAGDI::ag_stop_run()
{
    AG_GoStep_hook(AG_STOPRUN, 0, nullptr);
}

void VAGDI::slot_set_breakpoint(int addr)
{
    set_breakpoint(addr);
}

void VAGDI::slot_kill_breakpoint(int addr)
{
    kill_breakpoint(addr);
}

void VAGDI::slot_enable_breakpoint(int addr)
{
    enable_breakpoint(addr);
}

void VAGDI::slot_disable_breakpoint(int addr)
{
    disable_breakpoint(addr);
}

void VAGDI::slot_start(QString path)
{
	qDebug() << "run thread ID = " << QThread::currentThreadId();
    if(_is_debug == false){
        load_library();
        EnumUv351();
        AG_init(path);
        _is_debug = true;
    }else{
        emit signal_runing(true);
        ag_go_breakpoint();
        emit signal_runing(false);
        emit signal_ag_update_pc(_pc & 0x00FFFFFF);
    }
}

void VAGDI::slot_stop()
{
    emit signal_runing(true);
    ag_stop();
    emit signal_runing(false);
}

void VAGDI::slot_ag_step_out()
{
    emit signal_runing(true);
    ag_step_out();
    emit signal_runing(false);
    emit signal_ag_update_pc(_pc & 0x00FFFFFF);
}

void VAGDI::slot_ag_step_into()
{
    emit signal_runing(true);
    ag_step_into();
    emit signal_runing(false);
    emit signal_ag_update_pc(_pc & 0x00FFFFFF);
}

void VAGDI::slot_ag_step_over()
{
    emit signal_runing(true);
    ag_step_over();
    emit signal_runing(false);
    emit signal_ag_update_pc(_pc & 0x00FFFFFF);
}

char *VAGDI::new_string(const char *init_string, int size)
{
    char * result;
    result = new char[size];
    strcpy(result, init_string);
    return result;
}

void VAGDI::write_proc(QString path)
{
    QString text = VFunctions::read_file_text(path);
    QRegularExpression reg(":(\\w\\w)(\\w\\w\\w\\w)(\\w\\w)(\\w+)(\\w)");
    // 1 => length
    // 2 => addr
    // 3 => type
    // 4 => data
    // 5 =>
    QRegularExpressionMatch match;
    match = reg.match(text);
    while (match.hasMatch()) {
        int len = match.captured(1).toInt(nullptr, 16);
        int addr = match.captured(2).toInt(nullptr, 16);
        int type = match.captured(3).toInt(nullptr, 16);
        QString data = match.captured(4);
        UC8* temp = new UC8[len];
        if(type == 0){

            for (int i = 0; i < data.length() / 2; i++) {
                QString hex = data.mid(i * 2, 2);
                temp[i] = hex.toInt(nullptr, 16);
            }
            GADR pA;
            pA.Adr = 0xFF000000 | addr;
            AG_MemAcc_hook(AG_WROPC, temp, &pA, len);
        }
        if(temp)
            delete temp;

        match = reg.match(text, match.capturedEnd());
    }


    memset(&_ret_symbol, 0, 0xFFFF);
    memset(&_call_symbol, 0, 0xFFFF);
    VFunctions::get_asm_symbol(path, _ret_symbol, _call_symbol);
}

void VAGDI::set_breakpoint(int addr)
{
    
    if(_bp_head == nullptr){
		_bp_head = new AG_BP;
        _bp_head->Adr = 0xff000000 | addr;
        _bp_head->enabled = 1;
        _bp_head->next = nullptr;
        _bp_head->prev = nullptr;
        _bp_head->rcount = 1;
        _bp_head->ocount = 1;
        _bp_head->type = 0;
    }else{
		auto last = get_bp_last();
		if(last == nullptr) return;
        last->next = new AG_BP;
        last->next->prev = last;
		last->next->next = nullptr;
        last->next->Adr = 0xff000000 | addr;
        last->next->enabled = 1;
        last->next->rcount = 1;
        last->next->ocount = 1;
        last->next->type = 0;
    }


}

bool VAGDI::kill_breakpoint(int addr)
{
	addr = addr | 0xFF000000;
    auto temp = _bp_head;
    do{
        if(temp->Adr == addr){
            if(temp == _bp_head){
                // 头节点
                _bp_head = _bp_head->next;
                delete _bp_head;
                return true;
            }else if(temp->next == nullptr){
                // 尾节点
                temp->prev->next = nullptr;
                delete temp;
                return true;
            }else{
                // 中间节点
				temp->prev->next = temp->next;
				temp->next->prev = temp->prev;
				delete temp;
				return true;
            }
        }
        temp = temp->next;
    }while(temp);
    return false;
}

void VAGDI::enable_breakpoint(int addr)
{
    auto temp = _bp_head;
    while(temp){
        if(temp->Adr == addr){
            temp->enabled = 1;
            return;
        }
        temp = temp->next;
    }
}

void VAGDI::disable_breakpoint(int addr)
{
    auto temp = _bp_head;
    while(temp){
        if(temp->Adr == addr){
            temp->enabled = 0;
            return;
        }
        temp = temp->next;
    }
}

AG_BP * VAGDI::get_bp_last()
{
    auto temp = _bp_head;
    while(temp){
        if(temp->next == nullptr){
            return temp;
        }
        temp = temp->next;
    }
    return _bp_head;
}

int VAGDI::AG_init(QString path)
{
    unsigned int result;


    // 重置
    //1. 	AG_Init  	nCode:1037 	AG_EXECITEM -> AG_RESET
    result = AG_Init_hook(1037, nullptr);
    qDebug() << result;

    // 初始化项目
    // 	获取 Menu
    //2.	AG_Init 	nCode:775
    //	0xFF00	AG_INITITEM
    //	0x00FF	AG_INITMENU

    //	获取 DlgUpdate
    //	AG_Init 	nCode:776
    //	0xFF00	AG_INITITEM
    //	0x00FF	AG_INITEXTDLGUPD

    // 设置主窗口句柄
    //	AG_Init 	nCode:777
    //	0xFF00	AG_INITITEM
    //	0x00FF	AG_INITMHANDLEP
    //    result = AG_Init_hook(AG_INITITEM|AG_INITMHANDLEP, nullptr);
    //    qDebug() << result;
//    result = AG_Init_hook(AG_INITITEM|AG_INITMHANDLEP, (void *)this->winId());
//    qDebug() << result;

    // 设置主窗口句柄
    //	AG_Init 	nCode:778
    //	0xFF00	AG_INITITEM
    //	0x00FF	AG_INITMENU
    result = AG_Init_hook(AG_INITITEM|AG_INITPHANDLEP, (void *)_main_handle);
    qDebug() << result;

    // 设置指向agdi实例句柄的指针
    //	AG_Init 	nCode:779
    //	0xFF00	AG_INITITEM
    //	0x00FF	AG_INITINSTHANDLE
    result = AG_Init_hook(AG_INITITEM|AG_INITBPHEAD, (void*)nullptr);
    //qDebug() << result;

    // 指向BP列表头的指针
    //	AG_Init 	nCode:782
    //	0xFF00	AG_INITITEM
    //	0x00FF	AG_INITBPHEAD





//    auto bp = new AG_BP;
//    bp->Adr = 0xff00839;
//    bp->enabled = 1;
//    bp->next = nullptr;
//    bp->prev = nullptr;
//    bp->rcount = 1;
//    bp->ocount = 1;
//    bp->type = 0;

    //&list[0][0] = new AG_BP;

    //QMessageBox::warning(this, "", QString::number(sizeof(AG_BP)));
    result = AG_Init_hook(AG_INITITEM|AG_INITBPHEAD, &_bp_head);
    qDebug() << result;

    // 指向程序计数器的指针
    //	AG_Init 	nCode:783
    //	0xFF00	AG_INITITEM
    //	0x00FF	AG_INITCURPC
    result = AG_Init_hook(AG_INITITEM|AG_INITCURPC, (void*)&_pc);
    qDebug() << result;

    // oEvents函数指针
    //	AG_Init 	nCode:784
    //	0xFF00	AG_INITITEM
    //	0x00FF	AG_INITDOEVENTS

    // 已注册sendmessage的消息
    //	AG_Init 	nCode:785
    //	0xFF00	AG_INITITEM
    //	0x00FF	AG_INITUSRMSG
    result = AG_Init_hook(AG_INITITEM|AG_INITUSRMSG, (void *)100);
    qDebug() << result;


    // 指向回调函数的指针
    //	AG_Init 	nCode:786
    //	0xFF00	AG_INITITEM
    //	0x00FF	AG_INITCALLBACK
    result = AG_Init_hook(AG_INITITEM|AG_INITCALLBACK, (void *)callback);
    qDebug() << result;


    // 	初始化并启动目标
    //3.	AG_Init 	nCode:256
    result = AG_Init_hook(AG_INITFEATURES, nullptr);
    qDebug() << result;
    qDebug() << "启动完成";

    // 查询单片机所支持的功能
    //3.	AG_Init 	nCode:513
    //	AG_Init 	nCode:514
    //	AG_Init 	nCode:515
    //	AG_Init 	nCode:516
    //	AG_Init 	nCode:517
    //	AG_Init 	nCode:518
    //	AG_Init 	nCode:519

    result = AG_Init_hook(801, nullptr);
    qDebug() << result;

    // (U16 nCode, UL32 nAttr, GADR *pA);
     byte read[4] = {0x00, 0x00, 0x00, 0x00};
    GADR pA;
//    pA.Adr = 0;
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);

//    pA.Adr = 1;
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);

//    pA.Adr = 2;
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);

//    pA.Adr = 3;
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);

//    pA.Adr = 4;
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);
//    AG_MemAtt_hook(AG_GETMEMATT, 0, &pA);
//    AG_MemAcc_hook(AG_RDOPC, read, &pA, 4);
    //写入单片机程序
    //4.  AG_MemAcc
//    UC8 code1[3] = {0x2, 0x8, 0x38};
//    UC8 code2[12] = {0x78 ,0x7F ,0xE4 ,0xF6 ,0xD8 ,0xFD ,0x75 ,0x81 ,0x7 ,0x2 ,0x8 ,0x27};
//    UC8 code3[30] = {0x8 ,0x1E ,0xB2 ,0x91 ,0x12 ,0x8 ,0x1E ,0xB2 ,0x91 ,0x12 ,0x8 ,0x1E ,0xB2 ,0x91 ,0x12 ,0x8 ,0x1E ,0xB2 ,0x91 ,0x12 ,0x8 ,0x1E ,0xB2 ,0x91 ,0x12 ,0x8 ,0x1E ,0xB2 ,0x91};
//    UC8 code4[8] = {0x7F, 0xB4, 0x7E, 0x49, 0xDE, 0xFE, 0xDF, 0xFC};
//    UC8 code5[1] = {0x22};
//    UC8 code6[17] = {0x12 ,0x8 ,0x14 ,0xB2 ,0x91 ,0x12 ,0x8 ,0x0 ,0xB2 ,0x91 ,0x12 ,0x8 ,0x0 ,0xB2 ,0x91 ,0x80 ,0xF4};

//    //  (U16 nCode, UC8 *pB, GADR *pA, UL32 nMany);




//    pA.Adr = 0;
//    pA.nLen = 3;
//    pA.mSpace = 0;
//    result = AG_MemAcc_hook(AG_RDOPC, read, &pA, 3);
//    qDebug() << "read" << read[0] << "read" << read[1] << "read" << read[2];

//	pA.Adr = 0;
//	pA.nLen = 3;
//	pA.mSpace = 0;
//	result = AG_MemAcc_hook(AG_WROPC, code1, &pA, 3);
//	qDebug() << result;

//    pA.Adr = 0xFF000838;
//    result = AG_MemAcc_hook(AG_WROPC, code2, &pA,12);
//    qDebug() << result;

//    pA.Adr = 0xFF000800;
//    result = AG_MemAcc_hook(AG_WROPC, code3, &pA, 30);
//    qDebug() << result;

//    result = pA.Adr = 0xFF00081E;
//    AG_MemAcc_hook(AG_WROPC, code4, &pA, 8);
//    qDebug() << result;

//    pA.Adr = 0xFF000826;
//    result = AG_MemAcc_hook(AG_WROPC, code5, &pA, 1);
//    qDebug() << result;

//    pA.Adr = 0xFF000827;
//    result = AG_MemAcc_hook(AG_WROPC, code6, &pA, 17);
//    qDebug() << result;

    write_proc(path);


    result = AG_Init_hook(802, nullptr);
    qDebug() << result;

    // 重置
    //5. 	AG_Init 1037
    result = AG_Init_hook(1037, nullptr);
    qDebug() << result;

    return 0;
}
